package org.jeecg.modules.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.wms.entity.*;
import org.jeecg.modules.wms.mapper.WmsOutboundAllocationPlanMapper;
import org.jeecg.modules.wms.service.*;
import org.jeecg.modules.wms.vo.OutboundAllocationResult;
import org.jeecg.modules.wms.vo.WmsInventoryVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 出库分配方案服务实现
 */
@Slf4j
@Service
public class WmsOutboundAllocationPlanServiceImpl extends ServiceImpl<WmsOutboundAllocationPlanMapper, WmsOutboundAllocationPlan> 
    implements IWmsOutboundAllocationPlanService {

    @Autowired
    private IWmsOutboundService wmsOutboundService;
    
    @Autowired
    private IWmsOutboundDetailService wmsOutboundDetailService;
    
    @Autowired
    private IWmsInventoryService wmsInventoryService;
    
    @Autowired
    private IWmsWarehouseService warehouseService;
    
    @Autowired
    private IWmsWarehouseLocationService locationService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OutboundAllocationResult autoAllocateOutbound(String outboundId) {
        OutboundAllocationResult result = new OutboundAllocationResult();
        List<WmsOutboundAllocationPlan> allocationPlans = new ArrayList<>();
        List<OutboundAllocationResult.UnallocatedMaterial> unallocatedMaterials = new ArrayList<>();
        
        try {
            // 获取出库单信息
            WmsOutbound outbound = wmsOutboundService.getById(outboundId);
            if (outbound == null) {
                result.setSuccess(false);
                result.setMessage("出库单不存在");
                return result;
            }
            
            // 获取出库明细
            List<WmsOutboundDetail> outboundDetails = wmsOutboundDetailService.selectByOutboundId(outboundId);
            if (outboundDetails == null || outboundDetails.isEmpty()) {
                result.setSuccess(false);
                result.setMessage("出库单明细为空");
                return result;
            }
            
            // 清除已有的分配方案
            clearAllocationPlansAndReleaseInventory(outboundId);
            
            BigDecimal totalRequired = BigDecimal.ZERO;
            BigDecimal totalAllocated = BigDecimal.ZERO;
            boolean fullySatisfied = true;
            
            // 按物料分组处理
            Map<String, List<WmsOutboundDetail>> materialGroups = outboundDetails.stream()
                .collect(Collectors.groupingBy(WmsOutboundDetail::getMaterialCode));
            
            for (Map.Entry<String, List<WmsOutboundDetail>> entry : materialGroups.entrySet()) {
                String materialCode = entry.getKey();
                List<WmsOutboundDetail> details = entry.getValue();
                
                // 计算该物料的总需求数量
                BigDecimal materialRequiredQuantity = details.stream()
                    .map(WmsOutboundDetail::getQuantity)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                
                totalRequired = totalRequired.add(materialRequiredQuantity);
                
                // 获取第一个明细作为物料信息参考
                WmsOutboundDetail firstDetail = details.get(0);
                
                // 查询可用库存
                List<WmsInventoryVO> availableInventory = wmsInventoryService.queryAvailableInventoryForOutbound(
                    materialCode, firstDetail.getMaterialType().toString(), materialRequiredQuantity);
                
                BigDecimal materialAllocated = BigDecimal.ZERO;
                BigDecimal remainingQuantity = materialRequiredQuantity;
                
                // 生成分配方案
                for (WmsInventoryVO inventory : availableInventory) {
                    if (remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                        break;
                    }
                    
                    // 计算实际可分配数量（考虑预出库数量）
                    BigDecimal preOutboundQuantity = inventory.getPreOutboundQuantity() != null ? 
                        inventory.getPreOutboundQuantity() : BigDecimal.ZERO;
                    BigDecimal actualAvailable = inventory.getAvailableQuantity().subtract(preOutboundQuantity);
                    
                    if (actualAvailable.compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }
                    
                    BigDecimal allocationQuantity = actualAvailable.min(remainingQuantity);
                    
                    // 创建分配方案
                    WmsOutboundAllocationPlan plan = new WmsOutboundAllocationPlan();
                    plan.setOutboundId(outboundId);
                    plan.setOutboundNo(outbound.getOutboundNo());
                    plan.setMaterialCode(materialCode);
                    plan.setMaterialName(firstDetail.getMaterialName());
                    plan.setMaterialType(Integer.valueOf(firstDetail.getMaterialType()));
                    plan.setSpecification(firstDetail.getSpecification());
                    plan.setColor(firstDetail.getColor());
                    plan.setUnit(firstDetail.getUnit());
                    plan.setRequiredQuantity(materialRequiredQuantity);
                    plan.setWarehouseId(inventory.getWarehouseId());
                    plan.setWarehouseName(inventory.getWarehouseName());
                    plan.setLocationId(inventory.getLocationId());
                    plan.setLocationName(inventory.getLocationName());
                    plan.setAllocationQuantity(allocationQuantity);
                    plan.setInventoryId(inventory.getId());
                    plan.setAvailableQuantity(actualAvailable);
                    plan.setBatchNo(inventory.getBatchNo());
                    plan.setAllocationStatus(1); // 已分配
                    plan.setPriority(1);
                    plan.setCreateTime(new Date());
                    plan.setTenantId(Integer.valueOf(outbound.getTenantId()));
                    
                    allocationPlans.add(plan);
                    materialAllocated = materialAllocated.add(allocationQuantity);
                    remainingQuantity = remainingQuantity.subtract(allocationQuantity);
                }
                
                totalAllocated = totalAllocated.add(materialAllocated);
                
                // 检查是否完全满足需求
                if (remainingQuantity.compareTo(BigDecimal.ZERO) > 0) {
                    fullySatisfied = false;
                    
                    // 记录未满足的物料
                    OutboundAllocationResult.UnallocatedMaterial unallocated = 
                        new OutboundAllocationResult.UnallocatedMaterial();
                    unallocated.setMaterialCode(materialCode);
                    unallocated.setMaterialName(firstDetail.getMaterialName());
                    unallocated.setRequiredQuantity(materialRequiredQuantity);
                    unallocated.setAvailableQuantity(materialAllocated);
                    unallocated.setShortageQuantity(remainingQuantity);
                    unallocated.setUnit(firstDetail.getUnit());
                    
                    unallocatedMaterials.add(unallocated);
                }
            }
            
            // 保存分配方案
            if (!allocationPlans.isEmpty()) {
                saveAllocationPlansAndUpdateInventory(outboundId, allocationPlans);
            }
            
            // 设置结果
            result.setSuccess(true);
            result.setFullySatisfied(fullySatisfied);
            result.setAllocationPlans(allocationPlans);
            result.setUnallocatedMaterials(unallocatedMaterials);
            result.setTotalRequiredQuantity(totalRequired);
            result.setTotalAllocatedQuantity(totalAllocated);
            result.setTotalUnallocatedQuantity(totalRequired.subtract(totalAllocated));
            
            if (fullySatisfied) {
                result.setMessage("分配成功，完全满足出库需求");
            } else {
                result.setMessage("分配完成，但部分物料库存不足");
            }
            
        } catch (Exception e) {
            log.error("自动分配出库方案失败", e);
            result.setSuccess(false);
            result.setMessage("分配失败：" + e.getMessage());
        }
        
        return result;
    }

    @Override
    public List<WmsOutboundAllocationPlan> getByOutboundId(String outboundId) {
        return baseMapper.selectByOutboundId(outboundId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAllocationPlansAndUpdateInventory(String outboundId, List<WmsOutboundAllocationPlan> allocationPlans) {
        try {
            // 保存分配方案
            saveBatch(allocationPlans);
            
            // 更新库存预出库数量
            for (WmsOutboundAllocationPlan plan : allocationPlans) {
                WmsInventory inventory = wmsInventoryService.getById(plan.getInventoryId());
                if (inventory != null) {
                    BigDecimal currentPreOutbound = inventory.getPreOutboundQuantity() != null ? 
                        inventory.getPreOutboundQuantity() : BigDecimal.ZERO;
                    inventory.setPreOutboundQuantity(currentPreOutbound.add(plan.getAllocationQuantity()));
                    wmsInventoryService.updateById(inventory);
                }
            }
            
            return true;
        } catch (Exception e) {
            log.error("保存分配方案并更新库存失败", e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean clearAllocationPlansAndReleaseInventory(String outboundId) {
        try {
            // 获取现有分配方案
            List<WmsOutboundAllocationPlan> existingPlans = getByOutboundId(outboundId);
            
            // 释放预出库数量
            for (WmsOutboundAllocationPlan plan : existingPlans) {
                WmsInventory inventory = wmsInventoryService.getById(plan.getInventoryId());
                if (inventory != null) {
                    BigDecimal currentPreOutbound = inventory.getPreOutboundQuantity() != null ? 
                        inventory.getPreOutboundQuantity() : BigDecimal.ZERO;
                    BigDecimal newPreOutbound = currentPreOutbound.subtract(plan.getAllocationQuantity());
                    if (newPreOutbound.compareTo(BigDecimal.ZERO) < 0) {
                        newPreOutbound = BigDecimal.ZERO;
                    }
                    inventory.setPreOutboundQuantity(newPreOutbound);
                    wmsInventoryService.updateById(inventory);
                }
            }
            
            // 删除分配方案
            baseMapper.deleteByOutboundId(outboundId);
            
            return true;
        } catch (Exception e) {
            log.error("清除分配方案并释放库存失败", e);
            return false;
        }
    }

    @Override
    public boolean checkAllocationSufficiency(String outboundId) {
        List<WmsOutboundAllocationPlan> plans = getByOutboundId(outboundId);
        
        // 按物料分组检查
        Map<String, List<WmsOutboundAllocationPlan>> materialGroups = plans.stream()
            .collect(Collectors.groupingBy(WmsOutboundAllocationPlan::getMaterialCode));
        
        for (Map.Entry<String, List<WmsOutboundAllocationPlan>> entry : materialGroups.entrySet()) {
            List<WmsOutboundAllocationPlan> materialPlans = entry.getValue();
            
            if (materialPlans.isEmpty()) {
                continue;
            }
            
            BigDecimal requiredQuantity = materialPlans.get(0).getRequiredQuantity();
            BigDecimal allocatedQuantity = materialPlans.stream()
                .map(WmsOutboundAllocationPlan::getAllocationQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            if (allocatedQuantity.compareTo(requiredQuantity) < 0) {
                return false;
            }
        }
        
        return true;
    }

    @Override
    public List<WmsOutboundAllocationPlan> selectByOutboundIdAndUpdateBy(String id, String username) {
        return this.baseMapper.selectByOutboundIdAndUpdateBy(id, username);
    }
}
